import { OrthographicCamera, PerspectiveCamera, Renderer, Scene, WebGLRenderer } from 'three'
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
import State from 'three/examples/jsm/libs/stats.module';
export interface SceneConfig {
  canvas: HTMLCanvasElement;
  width?: number;
  height?: number;
}
export default class BaseScene {
  scene: Scene;
  renderer: WebGLRenderer;
  config: SceneConfig;
  camera: PerspectiveCamera | OrthographicCamera;
  controls: OrbitControls;
  animate: Function;
  stats: State;
  constructor(config: SceneConfig) {
    this.config = config;
    this.scene = new THREE.Scene();
    this.camera = this.initCamera();
    this.renderer = this.initRender();
    this.controls = this.initControls();
    this.scene.add(this.initLight());
    this.scene.add(this.camera);
    this.addStats();
  }
  private initRender() {
    const { config } = this;
    const renderer = new THREE.WebGLRenderer({
      canvas: config.canvas,
      // antialias: true,
    });
    renderer.setSize(config.width, config.height);
    return renderer;
  }
  private initCamera() {
    const { config } = this;
    const camera = new THREE.PerspectiveCamera(
      75,
      config.width / config.height,
      0.1,
      1000
    );
    camera.position.set(100, 100, 10);
    camera.lookAt(10, 0, 0);
    return camera;
  }
  private initLight() {
    //添加材质灯光阴影
    const light = new THREE.DirectionalLight(0xffffff, 1);
    light.position.setX(100);
    this.scene.add(light);
    return light;
  }
  private initControls() {
    const { camera, renderer } = this;
    return new OrbitControls(camera, renderer.domElement);
  }
  public run(): void {
    const { run, renderer, scene, camera } = this;
    requestAnimationFrame(run.bind(this));
    this.animate && this.animate();
    this.stats && this.stats.update();
    renderer.render(scene, camera);
  }
  private addStats() {
    const { renderer } = this;
    const stats = State();
    renderer.domElement.parentElement.appendChild(stats.dom);
    stats.dom.style.position = 'absolute';
    this.stats = stats;
  }

  public resetSize(width: number, height: number): void {
    const { renderer, camera } = this;
    camera['aspect'] = width / height;
    camera.updateProjectionMatrix();
    renderer.setSize(width, height);
  }
}
